package main

import (
	"math"
	"os"
	"server_cluster/common/logger"
	//"server_cluster/gate/db"
	"server_cluster/gate/gate_config"
	"strings"

	"github.com/jszwec/csvutil"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	gorm_logger "gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
)

const (
	DbInsertBatchSize = 100
)

var (
	DB           *gorm.DB = nil
	TableLoadMap          = make(map[string]struct{})
)

func main() {
	gate_config.InitConfig()
	logger.InitLogger("gate_data_config", gate_config.GetConfig().LOG_LEVEL)
	defer logger.CloseLogger()

	var gormLogger gorm_logger.Interface = nil
	if logger.LOG.Level == logger.DEBUG {
		gormLogger = gorm_logger.Default.LogMode(gorm_logger.Info)
	}
	dbuser := gate_config.DBUSER_PROD
    if gate_config.CONF.DEV_ENV {
        dbuser = gate_config.DBUSER_DEV
    }
	gormDb, err := gorm.Open(mysql.Open(dbuser+gate_config.GetConfig().DBHOST), &gorm.Config{
		Logger: gormLogger,
	})
	if err != nil {
		panic(err)
	}
	DB = gormDb

	// !!!新添加的配置表加在这里!!!
}

func LoadTable[T any](name string, fileName string) {
	logger.Info("start to load table, name: %v", name)
	// 文件预处理
	fileData, err := os.ReadFile(gate_config.GetConfig().ConfigTablePath + "/" + fileName + ".csv")
	if err != nil {
		panic(err)
	}
	// 去除UTF8的BOM头
	if fileData[0] == 0xEF && fileData[1] == 0xBB && fileData[2] == 0xBF {
		fileData = fileData[3:]
	}
	lineList := make([]string, 0)
	var lineTemp strings.Builder
	skipLF := false
	for _, c := range fileData {
		if !skipLF && c == '\n' {
			lineList = append(lineList, lineTemp.String())
			lineTemp.Reset()
			continue
		}
		// 处理表头的行内换行
		if c == '"' {
			skipLF = !skipLF
		}
		lineTemp.WriteByte(c)
	}
	// 特殊处理常量表的表头
	if name == "const" {
		lineList = append([]string{""}, lineList...)
	}
	if len(lineList) < 4 {
		panic("table format error")
	}
	var standardCsvData strings.Builder
	for index, line := range lineList {
		// 去除第一三四行的内容变成标准格式的csv
		if index == 0 || index == 2 || index == 3 {
			continue
		}
		// 去除第一列为空的行
		if len(line) == 0 || line[0] == ',' {
			continue
		}
		standardCsvData.WriteString(line)
		standardCsvData.WriteString("\n")
	}
	// csv解析
	list := make([]*T, 0)
	err = csvutil.Unmarshal([]byte(standardCsvData.String()), &list)
	if err != nil {
		panic(err)
	}
	logger.Debug("read table from excel ok, name: %v, list: %v", name, list)
	// 写入数据库
	_, exist := TableLoadMap[name]
	if !exist {
		if DB.Migrator().HasTable(new(T)) {
			err = DB.Migrator().DropTable(new(T))
			if err != nil {
				panic(err)
			}
		}
		err = DB.Migrator().CreateTable(new(T))
		if err != nil {
			panic(err)
		}
	}
	listLength := len(list)
	numBatch := int(math.Ceil(float64(listLength) / float64(DbInsertBatchSize)))
	for i := 0; i < numBatch; i++ {
		from := i * DbInsertBatchSize
		to := int(math.Min(float64((i+1)*DbInsertBatchSize), float64(listLength)))
		batch := list[from:to]
		err = DB.CreateInBatches(batch, len(batch)).Error
		if err != nil {
			panic(err)
		}
	}
	TableLoadMap[name] = struct{}{}
	logger.Debug("write table to db ok, name: %v, table: %v", name, any(new(T)).(schema.Tabler).TableName())
	logger.Info("load table ok, name: %v", name)
}
